#include "util.hpp"
#include "level.hpp"
#include "format.hpp"
#include "message.hpp"
#include "sink.hpp"
#include "logger.hpp"


void Test01()
{
    //测试实用接口
    std::cout<<mjwlog::util::Date::gettime()<<std::endl;
    std::string pathname="./abc/bcd/a.txt";
    mjwlog::util::File::createDirectory(mjwlog::util::File::path(pathname));
}

void Test02()
{
    //测试日志等级转换
    std::cout<<mjwlog::LogLevel::toString(mjwlog::LogLevel::value::DEBUG)<<std::endl;
    std::cout<<mjwlog::LogLevel::toString(mjwlog::LogLevel::value::INFO)<<std::endl;
    std::cout<<mjwlog::LogLevel::toString(mjwlog::LogLevel::value::WARN)<<std::endl;
    std::cout<<mjwlog::LogLevel::toString(mjwlog::LogLevel::value::ERROR)<<std::endl;
    std::cout<<mjwlog::LogLevel::toString(mjwlog::LogLevel::value::FATAL)<<std::endl;
    std::cout<<mjwlog::LogLevel::toString(mjwlog::LogLevel::value::OFF)<<std::endl;
}

void Test03()
{
    //先定义出一个日志消息，再定义一个Format格式化器，通过Format格式化器的成员函数format将日志消息
    //格式化进行返回相应的数据
    mjwlog::LogMsg msg(mjwlog::LogLevel::value::INFO,51,"main.c","root","格式化功能测试");
    //mjwlog:: Formatter fmt; --常规测试
    //mjwlog::Formatter fmt("abc%%abc[%d{%H:%M:%S}]%m%n");//非格式化字符显示和%%处理
    //mjwlog::Formatter fmt("abc%%abc[%d{%H:%M:%S}]%m%n{");//子规则格式测试
    //mjwlog::Formatter fmt("abc%%abc[%d{%H:%M:%S}]%m%");//格式化字符不全测试
    mjwlog::Formatter fmt("abc%%abc[%d{%H:%M:%S}]%m%g");
    std::string str=fmt.format(msg);
    std::cout<<str<<std::endl;
}

void Test04()
{
    mjwlog::LogMsg msg(mjwlog::LogLevel::value::INFO,51,"main.c","root","格式化功能测试...");
    mjwlog::Formatter fmt;
    std::string str=fmt.format(msg);
    mjwlog::LogSink::ptr stdout_lsp=mjwlog::SinkFactory::create<mjwlog::StdoutSink>();
    mjwlog::LogSink::ptr file_lsp=mjwlog::SinkFactory::create<mjwlog::FileSink>("./logfile/test.log");
    mjwlog::LogSink::ptr roll_lsp=mjwlog::SinkFactory::create<mjwlog::RollBySizeSink>("./logfile/roll-",1024*1024);
    stdout_lsp->log(str.c_str(),str.size());
    file_lsp->log(str.c_str(),str.size());
    size_t cursize=0;
    size_t count=0;
    while(cursize<1024*1024*10)
    {
        std::string tmp=str+std::to_string(count++);
        roll_lsp->log(tmp.c_str(),tmp.size());
        cursize+=tmp.size();
    }
}
/*
    扩展一个以时间作为文件滚动切换类型的日志落地模块
    1.以时间进行文件滚动，实际上是以时间段进行滚动
    实现思想：以当前系统时间，取模时间段大小，可以得到当前时间段是第几个时间段
    每次以当前系统时间取模，判断与当前文件的时间段是否一致，不一致则代表不是同一个时间段
*/ 
enum class TimeGap
{
    GAP_SECOND,
    GAP_MINUTE,
    GAP_HOUR,
    GAP_MDAY
};
class RollByTimeSink:public mjwlog::LogSink
{
    public:
        RollByTimeSink(const std::string& basename,TimeGap gap_type):_basename(basename)
        {
            switch(gap_type)
            {
                case TimeGap::GAP_SECOND: _gap_size=1;break;
                case TimeGap::GAP_MINUTE: _gap_size=60;break;
                case TimeGap::GAP_HOUR: _gap_size=3600;break;
                case TimeGap::GAP_MDAY: _gap_size=3600*24;break;   
            }
            _cur_gap=_gap_size==1? mjwlog::util::Date::gettime():mjwlog::util::Date::gettime()%_gap_size;
            std::string filename=createNewFile();
            mjwlog::util::File::createDirectory(mjwlog::util::File::path(filename));
            _ofs.open(filename,std::ios::binary | std::ios::app);
            assert(_ofs.is_open());
        }

        //将日志消息写入到标准输出，判断当前时间是否是当前文件的时间段，不是则切换文件
        void log(const char *data,size_t len)
        {
            time_t cur=mjwlog::util::Date::gettime();
            if((cur%_gap_size)!=_cur_gap)
            {
                _ofs.close();
                std::string filename=createNewFile();
                _ofs.open(filename,std::ios::binary | std::ios::app);
                assert(_ofs.is_open());
            }
            _ofs.write(data,len);
            assert(_ofs.good());
        }
    private:
        std::string createNewFile()
        {
            time_t t=mjwlog::util::Date::gettime();
            struct tm lt;
            localtime_r(&t,&lt);
            std::stringstream filename;
            filename<<_basename;
            filename<<lt.tm_year+1900;
            filename<<lt.tm_mon+1;
            filename<<lt.tm_mday;
            filename<<lt.tm_hour;
            filename<<lt.tm_min;
            filename<<lt.tm_sec;
            filename<<".log";
            return filename.str();
        }
    private:
        std::string _basename;
        std::ofstream _ofs;
        size_t _cur_gap;//当前是第几个时间段
        size_t _gap_size;//时间段的大小
};

void Test05()
{
    mjwlog::LogMsg msg(mjwlog::LogLevel::value::INFO,51,"main.c","root","格式化功能测试...");
    mjwlog::Formatter fmt;
    std::string str=fmt.format(msg);
    mjwlog::LogSink::ptr time_lsp=mjwlog::SinkFactory::create<RollByTimeSink>("./logfile/roll-",TimeGap::GAP_SECOND);
    time_t old=mjwlog::util::Date::gettime();
    while(mjwlog::util::Date::gettime()<old+5)
    {
        time_lsp->log(str.c_str(),str.size());
        usleep(1000);
    }
} 
void Test06()
{
    //测试同步日志器模块
    std::string logger_name="sync_logger";
    mjwlog::LogLevel::value limit=mjwlog::LogLevel::value::WARN;
    mjwlog::Formatter::ptr fmt(new mjwlog::Formatter("[%d{%H:%M:%S}][%c][%f:%l][%p]%m%n"));
    mjwlog::LogSink::ptr stdout_lsp=mjwlog::SinkFactory::create<mjwlog::StdoutSink>();
    mjwlog::LogSink::ptr file_lsp=mjwlog::SinkFactory::create<mjwlog::FileSink>("./logfile/test.log");
    mjwlog::LogSink::ptr roll_lsp=mjwlog::SinkFactory::create<mjwlog::RollBySizeSink>("./logfile/roll-",1024*1024);
    std::vector<mjwlog::LogSink::ptr> sinks={stdout_lsp,file_lsp,roll_lsp};
    mjwlog::Logger::ptr logger(new mjwlog::SyncLogger(logger_name,limit,fmt,sinks));

    logger->debug(__FILE__,__LINE__,"%s","测试日志");
    logger->info(__FILE__,__LINE__,"%s","测试日志");
    logger->warn(__FILE__,__LINE__,"%s","测试日志");
    logger->error(__FILE__,__LINE__,"%s","测试日志");
    logger->fatal(__FILE__,__LINE__,"%s","测试日志");
    size_t cursize=0,count=0;
    while(cursize<1024*1024*10)
    {
        logger->fatal(__FILE__,__LINE__,"测试日志-%d",count++);
        cursize+=100;
    }
}
void Test07()
{
    //测试建造者模式构建日志器
    std::unique_ptr<mjwlog::LoggerBuilder> build(new mjwlog::LocalLoggerBuilder());
    build->bulidLoggerName("sync_logger");
    build->buildLoggerLevel(mjwlog::LogLevel::value::WARN);
    build->buildFormatter("%m%n");
    build->buildLoggerType(mjwlog::LoggerType::LOGGER_SYNC);
    build->buildSink<mjwlog::FileSink>("./logfile/test.log");
    build->buildSink<mjwlog::RollBySizeSink>("./logfile/roll-",1024*1024);
    mjwlog::Logger::ptr logger=build->build();

    logger->debug(__FILE__,__LINE__,"%s","测试日志");
    logger->info(__FILE__,__LINE__,"%s","测试日志");
    logger->warn(__FILE__,__LINE__,"%s","测试日志");
    logger->error(__FILE__,__LINE__,"%s","测试日志");
    logger->fatal(__FILE__,__LINE__,"%s","测试日志");
    size_t cursize=0,count=0;
    while(cursize<1024*1024*10)
    {
        logger->fatal(__FILE__,__LINE__,"测试日志-%d",count++);
        cursize+=100;
    }
}
int main()
{
    //Test01();
    //Test02();
    //Test03();
    //Test04();
    //Test05();
    //Test06();
    Test07();
    return 0;
}